import pika
from xjlibrary.MRabbitMQ.center.BaseMQ import Init, OpenConnRabbitMQ, CloseConnRabbitMQ


class MQSendMessage(object):
    def __init__(self, cofig, queuetest):
        Init(cofig)
        self.ConnRabbitMQ = OpenConnRabbitMQ()
        self.channel = self.ConnRabbitMQ.channel()  # 创建频道
        self.queue = queuetest
        self.exchang = ""
        self.routing_key = ""
        self.nullExchange()
        self.queueresult = None

    def OpenConn(self):
        self.ConnRabbitMQ = OpenConnRabbitMQ()

    def __del__(self):
        self.channel.close()
        self.ConnRabbitMQ.close()

    def setQueue(self, queue):
        self.queue = queue
        self.routing_key = queue

    def set_queue_declare(self,Temporaryqueue=False,**kwargs):
        # 临时队列
        if Temporaryqueue:
            #无论什么时候我们连接到Rabbit我们需要一个空的、新的队列。为了实现这个我们可以创建个随机名的队列，
            # 或者，更好的 - 让服务端选择一个随机的队列名给我们，
            # 我们可以不给queue_declare方法设置queue参数来实现。

            # 一旦我们断开consumer连接，这个队列名将自动删除。这里有一个标识设置：
            """
              1、消费者订阅消息，先创建一个交换器，如果交换器已经存在即返回一个交换器。当然你可以passive
            为 true 如果 passive 为 true, 交换器已经存在返回一个已经存在的交换器，否则报错。我暂时不知道用在哪里，所以
            先记住一般情况下
            创建一个交换器，如果存在就返回一个已经存在的交换器，如果不存在则创建并返回。
            """
            result = self.channel.queue_declare(exclusive=True, durable=True,**kwargs)
            self.queueresult =result
            print("queue name is:"+result.method.queue)
            return result
        else:
            # 加入durable=True属性可以确保服务器队列不丢失
            result = self.channel.queue_declare(self.queue, durable=True,**kwargs)  # 声明或创建队列
            self.queueresult = result
            return result

    def get_message_count(self):
        if self.queueresult:
            return self.queueresult.method.message_count
        return None



    def setExchange(self, exchange, type):
        self.channel.exchange_declare(exchange=exchange, exchange_type=type)



    def fanoutExchange(self, exchange):
        """
        fanout exchange非常简单，你从这个名字中就能猜出来，它将从Producer方收到的消息广播给所有
        他知道的receiver方。而这正是我们的logger记录所需要的消息。
        :param exchange:
        :return:
        """
        self.exchang = exchange
        self.routing_key = ""
        self.setExchange(exchange, "fanout")

    def DirectExchange(self, exchange):
        """
        直接交换
        通过绑定的key确定分发到哪个队列
        :return:
        """
        self.exchang = exchange
        self.routing_key = ""
        self.setExchange(exchange, "direct")

    def TopicExchange(self, exchange):
        self.exchang = exchange
        self.routing_key = ""
        self.setExchange(exchange, "topic")


    def nullExchange(self):
        """
        这个exchange参数就是这个exchange的名字. 空字符串标识默认的或者匿名的exchange：
        如果存在routing_key, 消息路由到routing_key指定的队列中。
        :param exchange:
        :return:
        """
        self.exchang = ""
        self.routing_key = self.queue

    # def queueBind(self,queue):
    #     """
    #     服务器分配的队列queue = result.method.queue
    #     :param queue:
    #     :return:
    #     """
    #     self.channel.queue_bind(exchange=self.exchang,queue=queue)

    """
       消息持久化的注意点
       标记消息为持久化的并不能完全保证消息不会丢失，尽管告诉RabbitMQ保存消息到磁盘，
       当RabbitMQ接收到消息还没有保存的时候仍然有一个短暂的时间窗口. 
       RabbitMQ不会对每个消息都执行同步fsync(2) --- 可能只是保存到缓存cache还没有写入到磁盘中，
       这个持久化保证不是很强，但这比我们简单的任务queue要好很多，
       如果你想很强的保证你可以使用 publisher confirms
       """
    def publish(self, message,routing_key=None):
        """
        routing_key 在DirectExchange 模式下为每条消息配置
        Topic 模式下也需要匹配
        :param message:
        :param routing_key:
        :return:
        """
        if routing_key:
            self.routing_key = routing_key
        self.channel.basic_publish(exchange=self.exchang,
                                   routing_key=self.routing_key,
                                   body=message,
                                   properties=pika.BasicProperties(
                                       # 现在我们需要标记我们的消息为持久化的 - 通过设置 delivery_mode 属性为 2
                                       # 在开启服务器持久化以后
                                       delivery_mode=2,  # 设置消息为持久化的,
                                   )
                                   )

    def close(self):
        CloseConnRabbitMQ(self.ConnRabbitMQ)


# if __name__ == "__main__":
#     mqsm = MQSendMessage("../config/config.ini", "queuetest")
#     mqsm.setQueue(True)
#     mqsm.fanoutExchange("topic_logs")
#     num = 0
#     while True:
#         message = time.strftime('%H:%M:%S', time.localtime())
#         mqsm.publish(message,"kern.critical")
#         num += 1
#         print(num)
#         if num > 15:
#             break
#     mqsm.close()


# if __name__ == "__main__":
#     mqsm = MQSendMessage("../config/config.ini", "queuetest")
#     mqsm.setExchange("logs","fanout")
#     num=0
#     while True:
#         message = time.strftime('%H:%M:%S', time.localtime())
#         mqsm.publish(message)
#         num += 1
#         if num > 100:
#             break
#     mqsm.close()